feat(camera): round and feather the spotlight - #49
Open
Joilence wants to merge 1 commit into
Open
Conversation
The hole was a clip-path polygon, which can express exactly one shape: a hard-edged rectangle. Rounding its corners means emitting arcs by hand, and softening its edge is not possible at all. On a pill button the square cutout reads as a crop rather than as a highlight, and the one-pixel step from clear to full scrim is the harshest part of the effect. An SVG mask says both in two numbers. A white full-viewport rect keeps the scrim, a black rounded rect punches through it, and blurring that black rect is what feathers the hole. `radius` and `feather` are new options, both defaulted so existing callers get a softer effect without changing anything, and `feather: 0, radius: 0` restores the old look. The fades move to a cubic-bezier ease rather than ease-out, which is what makes the arrival read as a transition instead of a switch. Two details the mask needs and would fail quietly without. `color-interpolation-filters="sRGB"` because SVG defaults to linearRGB, which ramps the scrim far too fast right at the edge. And a filter region widened to 200%, because the default object bounding box clips the blur partway through its ramp on a small target. The four cutout defaults live in SPOTLIGHT_DEFAULTS and are passed through, since the page function is serialized and cannot close over module scope. Written twice, once in the signature and once as a fallback inside the page function, the two could disagree about what a default is. Measured against Chromium by reading pixels rather than markup. At the shipped defaults the scrim ramps 76, 80, 88, 98, 114, 134, 157, 180, 202, 221, 235, 245, 251 across roughly 26px, where before it stepped from 76 to 255 in a single pixel.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
The cutout was a
clip-path: polygon: a hard-edged rectangle, and nothing else. Rounding the corners means emitting arcs by hand; softening the edge is not possible at all. On a pill button that reads as a crop rather than a highlight, and the one-pixel step to full scrim is the harshest part of the effect.Same page, target and options, both sides calling argo's exported
spotlight(). Bottom row crops the cutout's corner, upscaled nearest-neighbour so the interpolator cannot invent the soft edge in question.Scrim luma across the cutout's left edge, at the shipped defaults:
What
radius: 0, feather: 0restores the old look exactly.color-interpolation-filters="sRGB": SVG defaults to linearRGB, which ramps the scrim far too fast at the hole's edge.featherstays under about a third of the cutout's shorter side, which the option documents.paddingis clamped for the first time here: onmaina large negative value still leaves a hole, under the mask it removes one.Known limitation:
svg.innerHTMLis a Trusted Types sink. On a page servingrequire-trusted-types-for 'script'the assignment throws,runCameraEffectswallows it, and no spotlight renders wheremain'sstyle.cssTextwould have. Left as is because building the nodes costs the mask markup's readability. Happy to convert.Test
main